/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package company.abstractClasses;

import comparators.CompanyAdquiredProfileCapableComparator;
import entities.CompanyAdquiredProfile;
import entities.CompanyAdquiredProfileFolder;
import entities.CompanyFolder;
import entities.Search;
import facades.AbstractFacade;
import facades.CompanyAdquiredProfileFolderFacade;
import interfaces.CompanyAdquiredProfileCapable;
import interfaces.SearchCapable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.event.Event;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.transaction.Transactional;
import qualifiers.CreatedEntityEvent;
import qualifiers.EditedEntityEvent;
import util.filter.CollectionsFilter;
import util.filter.Predicate;

/**
 *
 * @author damianfernandez
 * @param <T>
 * @param <F>
 * @param <C>
 * @param <P>
 */
public abstract class AbstractCompanyAdquiredProfileCapableFilterList<T extends CompanyAdquiredProfileCapable,F extends AbstractFacade<T>, C extends CompanyAdquiredProfileCapableComparator<T,P>, P extends Predicate<T> & SearchCapable> extends AbstractCandidateCapableFilterList<T, F, C, P>{
    @Inject
    private CompanyAdquiredProfileFolderFacade companyAdquiredProfileFolderFacade;
    @Inject
    @CreatedEntityEvent
    private Event<CompanyAdquiredProfileFolder> createdCompanyAdquiredProfileFolderEvent;
    @Inject
    @EditedEntityEvent
    private Event<CompanyFolder> editedCompanyFolderEvent;
    private String name;
    private Date fromDate;
    private Date toDate;
    private Boolean isRelated;
    
    //Collectors
    private String nameCollector;
    private Date fromDateCollector;
    private Date toDateCollector;
    private Boolean isRelatedCollector;
    
    private CompanyFolder copyToFolder;
    
    @Override
    public P getNewPredicateInstance(){
        P newPredicate=null;
        try {
            Type mySuperClass= this.getClass().getGenericSuperclass();
            while(!(mySuperClass instanceof ParameterizedType)){
                mySuperClass=((Class)mySuperClass).getGenericSuperclass();
            }
            Type predicateType = ((ParameterizedType)mySuperClass).getActualTypeArguments()[3];
            Constructor constructor=null;
            for(Constructor constructorIt: (Class.forName(predicateType.toString().split("<")[0])).getDeclaredConstructors()){
                if(constructorIt.getParameterTypes().length==5 && constructorIt.getParameterTypes()[0].isAssignableFrom(Search.class) && constructorIt.getParameterTypes()[1].isAssignableFrom(String.class) && constructorIt.getParameterTypes()[2].isAssignableFrom(Date.class) && constructorIt.getParameterTypes()[3].isAssignableFrom(Date.class) && constructorIt.getParameterTypes()[4].isAssignableFrom(Boolean.class)){
                    constructor=constructorIt;
                    break;
                }
            }
            if(constructor!=null){
                if(getPredicate()!=null){
                    newPredicate=(P)constructor.newInstance(getPredicate().getSearch(),name,fromDate,toDate,isRelated);
                }
                else{
                    newPredicate=(P)constructor.newInstance(new Search(),name,fromDate,toDate,isRelated);
                }
            }
        } catch (SecurityException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(AbstractCandidateCapableFilterList.class.getName()).log(Level.SEVERE, null, ex);
        }
        return newPredicate;
    }
    
    @Override
    public void reinitFilter(){
        super.reinitFilter();
        setNameCollector(null);
        setFromDateCollector(null);
        setToDateCollector(null);
        setIsRelatedCollector(null);
        name=null;
        fromDate=null;
        toDate=null;
        isRelated=null;
    }
    
    public void cancelProfileRequeriments(){
        setNameCollector(null);
        setFromDateCollector(null);
        setToDateCollector(null);
        setIsRelatedCollector(null);
    }
    
    public void removeProfileRequeriments(){
        setNameCollector(null);
        setFromDateCollector(null);
        setToDateCollector(null);
        setIsRelatedCollector(null);
        name=null;
        fromDate=null;
        toDate=null;
        isRelated=null;
        setEntityList(CollectionsFilter.filterOnNewCollection(getBaseEntityList(), getNewPredicateInstance()));
        sort();
    }
    
    public void addProfileRequeriments(){
        name=getNameCollector();
        fromDate=getFromDateCollector();
        toDate=getToDateCollector();
        isRelated=getIsRelatedCollector();
        setEntityList(CollectionsFilter.filterOnNewCollection(getBaseEntityList(), getNewPredicateInstance()));
        sort();
        setNameCollector(null);
        setFromDateCollector(null);
        setToDateCollector(null);
        setIsRelatedCollector(null);
    }
    
    @Transactional
    public void copyProfile(){
        if(getCopyToFolder()!=null && getChosenEntity().getCompanyAdquiredProfile()!=null){
            
            CompanyFolder folder=getCompany().getCompanyFolderList().get(getCompany().getCompanyFolderList().indexOf(getCopyToFolder()));
            CompanyAdquiredProfile adquired=getCompany().getCompanyAdquiredProfileList().get(getCompany().getCompanyAdquiredProfileList().indexOf(getChosenEntity().getCompanyAdquiredProfile()));
            CompanyAdquiredProfileFolder companyAdquiredProfileFolder=getAdquiredProfileFolderIfExists(adquired,folder);
            if(companyAdquiredProfileFolder==null){
                companyAdquiredProfileFolder=createCompanyAdquiredProfileFolder(adquired, folder);
                if(adquired.getCompanyAdquiredProfileFolderList()==null){
                    adquired.setCompanyAdquiredProfileFolderList(new ArrayList<CompanyAdquiredProfileFolder>());
                }
                adquired.getCompanyAdquiredProfileFolderList().add(companyAdquiredProfileFolder);
                if(folder.getCompanyAdquiredProfileFolderList()==null){
                    folder.setCompanyAdquiredProfileFolderList(new ArrayList<CompanyAdquiredProfileFolder>());
                }
                folder.getCompanyAdquiredProfileFolderList().add(companyAdquiredProfileFolder);
            }
            Collections.replaceAll(getCompany().getCompanyAdquiredProfileList(), adquired, adquired);
            Collections.replaceAll(getCompany().getCompanyFolderList(), folder, folder);
            editedCompanyFolderEvent.fire(folder);
        }
        setCopyToFolder(null);
        FacesContext context=FacesContext.getCurrentInstance();
        Locale locale=context.getViewRoot().getLocale();
        ResourceBundle rb = ResourceBundle.getBundle("messages", locale);
        String successMessage=rb.getString("CompanyAdquiredProfileCopied");
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, successMessage, successMessage);  
        context.addMessage(null, message); 
        context.renderResponse();
    }
    
    public CompanyAdquiredProfileFolder getAdquiredProfileFolderIfExists(CompanyAdquiredProfile adquiredProfile, CompanyFolder companyFolder){
        CompanyAdquiredProfileFolder adquiredProfileFolder=null;
        if(adquiredProfile.getCompanyAdquiredProfileFolderList()!=null){
            for (CompanyAdquiredProfileFolder companyAdquiredProfileFolderIt : adquiredProfile.getCompanyAdquiredProfileFolderList()) {
                if(companyAdquiredProfileFolderIt.getCompanyFolder().equals(companyFolder)){
                    adquiredProfileFolder=companyAdquiredProfileFolderIt;
                    break;
                }
            }
        }
        return adquiredProfileFolder;
    }
    
    @Transactional
    public CompanyAdquiredProfileFolder createCompanyAdquiredProfileFolder(CompanyAdquiredProfile profile, CompanyFolder folder){
        CompanyAdquiredProfileFolder adquiredProfileFolder=new CompanyAdquiredProfileFolder();
        adquiredProfileFolder.setCompanyAdquiredProfile(profile);
        adquiredProfileFolder.setCompanyFolder(folder);
        adquiredProfileFolder.setCreationDate(new Date());
        companyAdquiredProfileFolderFacade.create(adquiredProfileFolder);
        if(profile.getCompanyAdquiredProfileFolderList()==null){
            profile.setCompanyAdquiredProfileFolderList(new ArrayList<CompanyAdquiredProfileFolder>());
        }
        createdCompanyAdquiredProfileFolderEvent.fire(adquiredProfileFolder);
        return adquiredProfileFolder;
    } 

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the fromDate
     */
    public Date getFromDate() {
        return fromDate;
    }

    /**
     * @param fromDate the fromDate to set
     */
    public void setFromDate(Date fromDate) {
        this.fromDate = fromDate;
    }

    /**
     * @return the toDate
     */
    public Date getToDate() {
        return toDate;
    }

    /**
     * @param toDate the toDate to set
     */
    public void setToDate(Date toDate) {
        this.toDate = toDate;
    }

    /**
     * @return the isRelated
     */
    public Boolean getIsRelated() {
        return isRelated;
    }

    /**
     * @param isRelated the isRelated to set
     */
    public void setIsRelated(Boolean isRelated) {
        this.isRelated = isRelated;
    }

    /**
     * @return the copyToFolder
     */
    public CompanyFolder getCopyToFolder() {
        return copyToFolder;
    }

    /**
     * @param copyToFolder the copyToFolder to set
     */
    public void setCopyToFolder(CompanyFolder copyToFolder) {
        this.copyToFolder = copyToFolder;
    }

    /**
     * @return the nameCollector
     */
    public String getNameCollector() {
        return nameCollector;
    }

    /**
     * @param nameCollector the nameCollector to set
     */
    public void setNameCollector(String nameCollector) {
        this.nameCollector = nameCollector;
    }

    /**
     * @return the fromDateCollector
     */
    public Date getFromDateCollector() {
        return fromDateCollector;
    }

    /**
     * @param fromDateCollector the fromDateCollector to set
     */
    public void setFromDateCollector(Date fromDateCollector) {
        this.fromDateCollector = fromDateCollector;
    }

    /**
     * @return the toDateCollector
     */
    public Date getToDateCollector() {
        return toDateCollector;
    }

    /**
     * @param toDateCollector the toDateCollector to set
     */
    public void setToDateCollector(Date toDateCollector) {
        this.toDateCollector = toDateCollector;
    }

    /**
     * @return the isRelatedCollector
     */
    public Boolean getIsRelatedCollector() {
        return isRelatedCollector;
    }

    /**
     * @param isRelatedCollector the isRelatedCollector to set
     */
    public void setIsRelatedCollector(Boolean isRelatedCollector) {
        this.isRelatedCollector = isRelatedCollector;
    }
}
